#include "GuiComponent.h"
#include "MeshInstance.h"
#include "ResourceManager.h"
#include "ErrorLogger.h"

namespace SypX
{
	GuiComponent::GuiComponent(float w, float h):tex(0), width(w), height(h), wasIn(false)
	{
		mi = new MeshInstance();
		mi->useMesh(this);

		onDownCallBack = SYPXBIND(&GuiComponent::doNothing, this, SYPX_ARG1, SYPX_ARG2);
		onUpCallBack = SYPXBIND(&GuiComponent::doNothing, this, SYPX_ARG1, SYPX_ARG2);
		onInCallBack = SYPXBIND(&GuiComponent::doNothing, this, SYPX_ARG1, SYPX_ARG2);
		onOutCallBack = SYPXBIND(&GuiComponent::doNothing, this, SYPX_ARG1, SYPX_ARG2);

	}

	GuiComponent::~GuiComponent(void)
	{
		delete mi;
		assert(this->getNumRef() == 0 && "GuiComponent reference count not 0 upon deletion");
		ResourceManager::getSingleton()->removeResource( this );
	}

	MeshInstance* GuiComponent::getMeshInstance()
	{
		return mi;
	}

	bool GuiComponent::withinBounds(float x, float y)
	{
		const Vec4& pos = mi->getPositionRef();
		if (x > pos.x - width / 2 && x < pos.x + width / 2 && y > pos.y - height / 2 && y < pos.y + height / 2)
		{
			return true;
		}

		return false;
	}

	void GuiComponent::onUp(SypX::Event& e)
	{
		onUpCallBack(this, e);
	}

	void GuiComponent::onDown(SypX::Event& e)
	{
		onDownCallBack(this, e);
	}

	void GuiComponent::onIn(SypX::Event& e)
	{
		wasIn = true;
		onInCallBack(this, e);
	}

	void GuiComponent::onOut(SypX::Event& e)
	{
		wasIn = false;
		onOutCallBack(this, e);
	}

	bool GuiComponent::processInput(SypX::Event& e)
	{
		switch (e.type)
		{
			case SypX::TOUCHUP:
			case SypX::MOUSELEFTUP:
				if (withinBounds((float) e.location.x, (float) e.location.y))
				{
					onUp(e);
					return true;
				}
				break;
			case SypX::TOUCHDOWN:
			case SypX::MOUSELEFTDOWN:
				if (withinBounds((float) e.location.x, (float) e.location.y))
				{
					onDown(e);
					return true;
				}
				break;
			case SypX::TOUCHMOVE:
			case SypX::MOUSEMOVE:
				if(withinBounds((float) e.moved.curr.x, (float) e.moved.curr.y))
				{
					if(!wasIn)
					{
						onIn(e);
					}
				}
				else if(wasIn)
				{
					onOut(e);
				}
				break;
				default:
				break;
		}

		return false;
	}

	void GuiComponent::setTexture(SypX::Texture* t)
	{
		tex = t;
		mi->useTexture(t);
	}

	void GuiComponent::move(float x, float y)
	{
		mi->setPosition(SypX::Vec2(x,y));
		mi->update();
	}

	void GuiComponent::doNothing(GuiComponent* g, Event& e)
	{
	}
}
